package cim144.ctdp

import Chisel._
import chisel3.util.switch
//import chisel3._ // VecInit
//import chisel3.util._ // MuxCase
import freechips.rocketchip.tile._
import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy._ // LazyModule
import freechips.rocketchip.rocket._ //

class CIMcmdIO extends Bundle{
  val valid = Input(Bool())
  val ready = Output(Bool())
  val funct = Input(UInt(7.W))
  val rs1   = Bits(INPUT,64)
  val rs2   = Bits(INPUT,64)
}

class CIMmemIO extends Bundle{
  val req_valid = Output(Bool())
  val req_ready = Input(Bool())
  val req_addr  = Bits(OUTPUT,40)
  val req_cmd   = Bits(OUTPUT,5)
  val req_data  = Bits(OUTPUT,64)
  // input data
  val resp_valid= Input(Bool())
  val resp_data = Bits(INPUT,64)
}

class CIMctl2dtpIO extends Bundle{
  val custom_push   = Output(Bool())
  val custom_save   = Output(Bool())
  val custom_mvm    = Output(Bool())
  val custom_config = Output(Bool())
  val isidle        = Output(Bool())
  val ispush        = Output(Bool())
  val ismvm         = Output(Bool())
  val issave        = Output(Bool())
  val isconfig      = Output(Bool())
  val mem_valid     = Output(Bool())
  val mem_data      = Bits(OUTPUT,64)
  val mem_req_ready = Output(Bool())
  val mem_req_data  = Bits(OUTPUT,64)
  val rs1           = Bits(OUTPUT,64)
  val rs2           = Bits(OUTPUT,64)
}


class CIMController(implicit p: Parameters) extends Module {
  val io = IO{new Bundle {
    val cmd = new CIMcmdIO
    val mem = new CIMmemIO
    val busy = Output(Bool())
    // ctl2dtp
    val ctl = new CIMctl2dtpIO
    val dtp = Flipped(new CIMdtp2ctlIO)
    }
  }
  val idle::push ::save::mvm::config::Nil = Enum(5)
  val state    = RegInit(idle)
  io.ctl.isidle   := state === idle
  io.ctl.ispush   := state === push
  io.ctl.ismvm    := state === mvm
  io.ctl.issave   := state === save
  io.ctl.isconfig := state === config
  //*****1.1 decode*************
  val rv32_func7_0010001 = io.cmd.funct === "b0010001".U
  val rv32_func7_0010010 = io.cmd.funct === "b0010010".U
  val rv32_func7_0000001 = io.cmd.funct === "b0000001".U
  val rv32_func7_0000010 = io.cmd.funct === "b0000010".U
  io.ctl.custom_push   := rv32_func7_0010001 & io.ctl.isidle & io.cmd.valid & io.cmd.ready
  io.ctl.custom_save   := rv32_func7_0010010 & io.ctl.isidle & io.cmd.valid & io.cmd.ready
  io.ctl.custom_mvm    := rv32_func7_0000001 & io.ctl.isidle & io.cmd.valid & io.cmd.ready
  io.ctl.custom_config := rv32_func7_0000010 & io.ctl.isidle & io.cmd.valid & io.cmd.ready
  //*********** 1.2 finite state machine***********
  //val push_done = Wire(Bool());val save_done = Wire(Bool()); val mvm_done = Wire(Bool());
  switch(state){
    is(idle){ state :=  Mux(io.ctl.custom_push,push,
                        Mux(io.ctl.custom_save,save,
                        Mux(io.ctl.custom_mvm,mvm,
                        Mux(io.ctl.custom_config,config,idle))))}
    is(push){ state :=  Mux(io.dtp.push_done,idle,push)}
    is(save){ state :=  Mux(io.dtp.save_done,idle,save)}
    is(mvm) { state :=  Mux(io.dtp.mvm_done ,idle,mvm)}
    is(config){state:= idle}
  }
  //*************1.3 some output ************
  io.busy       :=  Mux(io.ctl.isidle,io.cmd.valid,true.B)
  io.cmd.ready  := io.ctl.isidle
  // ***********2. to datapath   ***********
  io.ctl.rs1 := io.cmd.rs1
  io.ctl.rs2 := io.cmd.rs2
  io.ctl.mem_valid      := io.mem.resp_valid
  io.ctl.mem_data       := io.mem.resp_data
  io.ctl.mem_req_ready  := io.mem.req_ready
  io.mem.req_cmd   := Mux(io.ctl.issave ,M_XWR, M_XRD)
  io.mem.req_addr  := io.dtp.baseAddr
  io.mem.req_valid := io.dtp.mem_req_valid
  io.mem.req_data  := io.dtp.mem_req_data
}
